1   /*
2    * Copyright (C) 2012 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect.testing.google;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.collect.Multimap;
23  import com.google.common.collect.testing.AbstractContainerTester;
24  import com.google.common.collect.testing.Helpers;
25  import com.google.common.collect.testing.SampleElements;
26  
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.Map;
31  import java.util.Map.Entry;
32  
33  /**
34   * Superclass for all {@code Multimap} testers.
35   *
36   * @author Louis Wasserman
37   */
38  @GwtCompatible
39  public abstract class AbstractMultimapTester<K, V, M extends Multimap<K, V>>
40      extends AbstractContainerTester<M, Map.Entry<K, V>> {
41  
42    private M multimap;
43  
44    protected M multimap() {
45      return multimap;
46    }
47  
48    /**
49     * @return an array of the proper size with {@code null} as the key of the
50     * middle element.
51     */
52    protected Map.Entry<K, V>[] createArrayWithNullKey() {
53      Map.Entry<K, V>[] array = createSamplesArray();
54      final int nullKeyLocation = getNullLocation();
55      final Map.Entry<K, V> oldEntry = array[nullKeyLocation];
56      array[nullKeyLocation] = Helpers.mapEntry(null, oldEntry.getValue());
57      return array;
58    }
59  
60    /**
61     * @return an array of the proper size with {@code null} as the value of the
62     * middle element.
63     */
64    protected Map.Entry<K, V>[] createArrayWithNullValue() {
65      Map.Entry<K, V>[] array = createSamplesArray();
66      final int nullValueLocation = getNullLocation();
67      final Map.Entry<K, V> oldEntry = array[nullValueLocation];
68      array[nullValueLocation] = Helpers.mapEntry(oldEntry.getKey(), null);
69      return array;
70    }
71  
72    /**
73     * @return an array of the proper size with {@code null} as the key and value of the
74     * middle element.
75     */
76    protected Map.Entry<K, V>[] createArrayWithNullKeyAndValue() {
77      Map.Entry<K, V>[] array = createSamplesArray();
78      final int nullValueLocation = getNullLocation();
79      array[nullValueLocation] = Helpers.mapEntry(null, null);
80      return array;
81    }
82  
83    protected V getValueForNullKey() {
84      return getEntryNullReplaces().getValue();
85    }
86  
87    protected K getKeyForNullValue() {
88      return getEntryNullReplaces().getKey();
89    }
90  
91    private Entry<K, V> getEntryNullReplaces() {
92      Iterator<Entry<K, V>> entries = getSampleElements().iterator();
93      for (int i = 0; i < getNullLocation(); i++) {
94        entries.next();
95      }
96      return entries.next();
97    }
98  
99    protected void initMultimapWithNullKey() {
100     resetContainer(getSubjectGenerator().create(createArrayWithNullKey()));
101   }
102 
103   protected void initMultimapWithNullValue() {
104     resetContainer(getSubjectGenerator().create(createArrayWithNullValue()));
105   }
106 
107   protected void initMultimapWithNullKeyAndValue() {
108     resetContainer(getSubjectGenerator().create(createArrayWithNullKeyAndValue()));
109   }
110 
111   protected SampleElements<K> sampleKeys() {
112     return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) getSubjectGenerator()
113         .getInnerGenerator()).sampleKeys();
114   }
115 
116   protected SampleElements<V> sampleValues() {
117     return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) getSubjectGenerator()
118         .getInnerGenerator()).sampleValues();
119   }
120 
121   @Override
122   protected Collection<Entry<K, V>> actualContents() {
123     return multimap.entries();
124   }
125 
126   // TODO: dispose of this once collection is encapsulated.
127   @Override
128   protected M resetContainer(M newContents) {
129     multimap = super.resetContainer(newContents);
130     return multimap;
131   }
132 
133   protected Multimap<K, V> resetContainer(Entry<K, V>... newContents) {
134     multimap = super.resetContainer(getSubjectGenerator().create(newContents));
135     return multimap;
136   }
137 
138   /** @see AbstractContainerTester#resetContainer() */
139   protected void resetCollection() {
140     resetContainer();
141   }
142 
143   protected void assertGet(K key, V... values) {
144     assertGet(key, Arrays.asList(values));
145   }
146 
147   protected void assertGet(K key, Collection<V> values) {
148     assertThat(multimap().get(key)).has().exactlyAs(values);
149 
150     if (!values.isEmpty()) {
151       assertThat(multimap().asMap().get(key)).has().exactlyAs(values);
152       assertFalse(multimap().isEmpty());
153     } else {
154       assertThat(multimap().asMap().get(key)).isNull();
155     }
156 
157     // TODO(user): Add proper overrides to prevent autoboxing.
158     // Truth+autoboxing == compile error. Cast int to long to fix:
159     assertThat(multimap().get(key).size()).isEqualTo((long) values.size());
160 
161     assertEquals(values.size() > 0, multimap().containsKey(key));
162     assertEquals(values.size() > 0, multimap().keySet().contains(key));
163     assertEquals(values.size() > 0, multimap().keys().contains(key));
164   }
165 }